// *****************************************************************************
// 
//  Copyright 2006, Liu Xiao Wei
//  All rights reserved. The software and associated documentation 
//  supplied hereunder are the proprietary information of Liu Xiao Wei
//  and are supplied subject to licence terms.
// 
//  SharpFormEditorDemo
// *****************************************************************************

using System;
using System.Windows.Forms;
using System.Reflection;
using System.Collections;
using System.ComponentModel;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Diagnostics;
using System.Drawing;
using System.ComponentModel.Design;
using System.Runtime.Serialization;
using CXMLStudioIDE.DataAccessLayer;

namespace CXMLStudioIDE.Common.EntityProperties
{
    #region ControlFactory
    /// <summary>
    /// Summary description for FormControlFactory.
    /// </summary>
    public class ControlFactory
    {
        public static object CreateControl(string ctrlName, string partialName)
        {
            try
            {
                Control control;
                if (partialName.Equals("dummy"))
                {
                    control = new Button();
                }
                else
                {
                    switch (ctrlName)
                    {
                        case "Label":
                            control = new Label();
                            break;

                        case "TextBox":
                            control = new TextBox();
                            break;

                        case "PictureBox":
                            control = new PictureBox();
                            break;

                        case "ListView":
                            control = new ListView();
                            break;

                        case "ComboBox":
                            control = new ComboBox();
                            break;

                        case "Button":
                            control = new Button();
                            break;

                        case "CheckBox":
                            control = new CheckBox();
                            break;

                        case "MonthCalender":
                            control = new MonthCalendar();
                            break;

                        case "DateTimePicker":
                            control = new DateTimePicker();
                            break;

                        default:
                            //control = (Control) Activator.CreateInstance(Assembly.LoadWithPartialName(partialName).GetType(partialName + "." + ctrlName));
                            control = (Control)Activator.CreateInstance(Assembly.Load(partialName).GetType(partialName + "." + ctrlName));
                            break;
                    }
                }
                return control;
            }
            catch (Exception exception)
            {
                Debug.WriteLine("create control failed:" + exception.Message);
                return new Control();
            }
        }

        public static object CreateControl(IDesignerHost host, Type t, string controlname)
        {
            Control c = null;
            c = (Control)host.CreateComponent(t, controlname);
            c.Parent = (Form)host.RootComponent;
            return c;
        }

        public static Type GetControlTypeFromName(string ctrl_name)
        {
            string prefix = "";
            Type type = null;
            prefix = ctrl_name.Substring(0, ctrl_name.IndexOf('_'));
            if (prefix.Length > 0)
            {
                switch (prefix)
                {
                    case "txt":
                        type = typeof(TextBox);
                        break;
                    case "lbl":
                        type = typeof(Label);
                        break;
                    case "cmb":
                        type = typeof(ComboBox);
                        break;
                    case "chk":
                        type = typeof(CheckBox);
                        break;
                    case "rb":
                        type = typeof(RadioButton);
                        break;
                    case "dtp":
                        type = typeof(DateTimePicker);
                        break;
                }
            }
            return type;
        }

        public static string GetPrefixFromControlTypeName(string ControlTypeName)
        {
            string name_preffix = null;
            switch (ControlTypeName)
            {
                case "ComboBox":
                    name_preffix = "cmb_";
                    break;
                case "RadioButton":
                    name_preffix = "rb_";
                    break;
                case "TextBox":
                    name_preffix = "txt_";
                    break;
                case "Label":
                    name_preffix = "lbl_";
                    break;
                case "CheckBox":
                    name_preffix = "chk_";
                    break;
                case "DateTimePicker":
                    name_preffix = "dtp_";
                    break;
            }
            return name_preffix;
        }

        #region serialization related methods

        public static void CopyCtrls2ClipBoard(object[] ctrls)
        {
            CBFormCtrls data = new CBFormCtrls(ctrls);
            IDataObject obj2 = new DataObject();
            obj2.SetData(CBFormCtrls.Format.Name, true, data);
            Clipboard.SetDataObject(obj2, true);
        }

        public static void DeserializeFormFromFile(Form frm, string fileName)
        {
            Debug.Assert(frm != null);
            frm.Controls.Clear();
            Stream serializationStream = File.Open(fileName, FileMode.Open);
            BinaryFormatter formatter = new BinaryFormatter();
            CBFormCtrls ctrls = formatter.Deserialize(serializationStream) as CBFormCtrls;
            serializationStream.Close();
            foreach (CBFormCtrlItem item in ctrls.CtrlItemList)
            {
                object ctrl = CreateControl(item.CtrlName, item.PartialName);
                SetControlProperties(ctrl, item.PropertyList);
                if (ctrl is Form)
                {
                    SetControlProperties(frm, item.PropertyList);
                }
                else if (ctrl is Control)
                {
                    frm.Controls.Add(ctrl as Control);
                }
            }
        }

        public static object[] GetCtrlsFromClipBoard()
        {
            ArrayList list = new ArrayList();
            IDataObject dataObject = Clipboard.GetDataObject();
            if (dataObject.GetDataPresent(CBFormCtrls.Format.Name))
            {
                CBFormCtrls data = dataObject.GetData(CBFormCtrls.Format.Name) as CBFormCtrls;
                foreach (CBFormCtrlItem item in data.CtrlItemList)
                {
                    Control ctrl = CreateControl(item.CtrlName, item.PartialName) as Control;
                    SetControlProperties(ctrl, item.PropertyList);
                    list.Add(ctrl);
                }
            }
            return list.ToArray();
        }

        public static void SerializeForm2File(Form frm, string fileName)
        {
            try
            {
                ArrayList list = new ArrayList(frm.Controls);
                list.Add(frm);
                CBFormCtrls graph = new CBFormCtrls(list.ToArray());
                Stream serializationStream = File.Open(fileName, FileMode.OpenOrCreate);
                new BinaryFormatter().Serialize(serializationStream, graph);
                serializationStream.Close();
            }
            catch (Exception exception)
            {
                Trace.WriteLine(exception.Message);
            }
        }

        public static byte[] SerializeControlToBin(object ctrl)
        {
            byte[] bytes = null;
            try
            {
                ArrayList list = new ArrayList();
                list.Add(ctrl);

                //To string
                CBFormCtrls graph = new CBFormCtrls(list.ToArray());
                MemoryStream memoryStream = new MemoryStream();
                BinaryFormatter bin = new BinaryFormatter();
                bin.Serialize(memoryStream, graph);
                bytes = memoryStream.ToArray();
                memoryStream.Close();
            }
            catch (Exception exception)
            {
                Trace.WriteLine(exception.Message);
            }
            return bytes;
        }

        private static CBFormCtrls BinToControls(byte[] bytes)
        {
            CBFormCtrls ctrls = null;
            try
            {
                MemoryStream stream = new MemoryStream();
                stream.Write(bytes, 0, bytes.Length);
                stream.Position = 0;
                BinaryFormatter formatter = new BinaryFormatter();
                ctrls = formatter.Deserialize(stream) as CBFormCtrls;
                stream.Close();
            }
            catch (SerializationException sex)
            {
                MessageBox.Show(sex.Message, "CXMLStudio Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return ctrls;
        }

        public static object DeserializeControlFromBin(byte[] bytes, IDesignerHost host, Type t, string controlname)
        {
            object ctrl = null;
            CBFormCtrls ctrls = null;
            ctrls = BinToControls(bytes);

            foreach (CBFormCtrlItem item in ctrls.CtrlItemList)
            {
                /** Validate if the control creation will be done through DesignerHost ***/
                if (host != null && t != null && controlname != null)
                {
                    ctrl = CreateControl(host, t, controlname);
                }
                else
                {
                    ctrl = CreateControl(item.CtrlName, item.PartialName);
                }
                SetControlProperties(ctrl, item.PropertyList);
            }
            return ctrl;
        }

        public static CBFormCtrlItem GetPropertiesFromBin(int i_EntityTypeVersionsID, string lineage, DisplayContext context, ControlType ctrl_type)
        {
            PropertiesDAL propDAL = new PropertiesDAL();
            byte[] bytes = null;
            CBFormCtrls ctrls = null;

            bytes = propDAL.GetBinaryControl(i_EntityTypeVersionsID, lineage, Convert.ToInt32(context),Convert.ToInt32(ctrl_type));
            if (bytes != null)
            {
                ctrls = BinToControls(bytes);
                foreach (CBFormCtrlItem item in ctrls.CtrlItemList)
                {
                    return item;
                }
            }
            return null;
        }

        #endregion

        public static object GetValueObjectFromString(Type T, string value, DataBinding binding)
        {
            switch (T.Name)
            {
                case "Char":
                    if (value.Length > 0 && Convert.ToChar(value) != '\0')
                    {
                        //return Enum.Parse(T, value);
                        return Convert.ToChar(value);
                    }
                    else
                        return ' ';
                case "Color":
                    Object colorObj = Activator.CreateInstance(T);
                    System.Drawing.ColorConverter CC = new ColorConverter();
                    object objColorProperty = CC.ConvertFromString(value);
                    return objColorProperty;
                case "ControlBindingsCollection":
                    if (binding != null)
                    {
                        Binding b = null;
                        foreach (MyBinding mb in binding.Bindings)
                        {
                            b = new Binding(mb.PropertyName, mb.DataSource, mb.DataMember);
                            return b;
                        }
                    }
                    break;
                default:

                    if (T.IsEnum)
                    {
                        Type enumType = T;
                        FieldInfo enumItem = enumType.GetField(value);
                        if (enumItem != null)
                        {
                            int enumValue = (int)enumItem.GetValue(enumType);
                            return enumValue;
                        }
                        break;
                    }
                    else
                    {
                        object O = null;
                        try
                        {
                            O = Convert.ChangeType(value, T);
                        }
                        catch (InvalidCastException inex)
                        {
                            inex = null;
                        }
                        return O;
                    }
            }
            return null;
        }

        public static string GetControlName(string lineage, Type t)
        {
            string name = null;
            string prefix = ControlFactory.GetPrefixFromControlTypeName(t.Name);
            if (prefix != null && prefix.Length > 0)
            {
                name = prefix + lineage;
            }
            return name;
        }

        public static void SetControlProperties(Control ctrl, PropertySet propertyValues)
        {
            try
            {
                PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(ctrl);

                foreach (PropertyInfo property in ctrl.GetType().GetProperties())
                {
                    if (property.CanWrite || property.Name == "DataBindings")
                    {
                        EntityProperty CurrentKeyValue = null;
                        CurrentKeyValue = propertyValues[property.Name];
                        if (CurrentKeyValue != null)
                        {
                            if (property.PropertyType.FullName.Equals(CurrentKeyValue.Type.FullName))
                            {
                                // Set properties on the dynamic control
                                //Debug.WriteLine(property.Name);
                                Type T = property.PropertyType;
                                object value = null;
                                if (CurrentKeyValue.Value != null)
                                {
                                    value = CurrentKeyValue.Value;
                                }
                                if (value != null)
                                {
                                    property.SetValue(ctrl, value, null);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message);
            }
        }

        public static void SetControlProperties(object ctrl, Hashtable propertyList)
        {
            foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(ctrl))
            {
                if (propertyList.Contains(descriptor.Name))
                {
                    object obj2 = propertyList[descriptor.Name];
                    try
                    {
                        /** Attention, If Location is set before Top, then
                         * Top overrides the top value set by location so
                         * skip it to keep the good one **/
                        if (descriptor.Name == "Top" && (int)descriptor.GetValue(ctrl) != 0)
                        {
                            continue;
                        }
                        descriptor.SetValue(ctrl, obj2);
                        continue;
                    }
                    catch (Exception exception)
                    {
                        Trace.WriteLine(exception.Message);
                        continue;
                    }
                }
            }
        }

    }

}
    #endregion